package com.societyGames.codeAlong.user
{
import com.societyGames.persist.IPersist;
import com.societyGames.persist.SharedObjectPersist;
import com.societyGames.system.EventObject;

import flash.events.Event;

public class PersistentUserData extends UserData
{
  private var _initializeCompletedEventObject:EventObject; //Initialize completed
  private var _saveCompletedEventObject:EventObject; //Save completed (or at least appears to have. Persists may have been bad.
  private var _saveFailedEventObject:EventObject;
  private var _sharedObjectPersist:SharedObjectPersist;
  private var _sharedObjectFlushEnabled:Boolean = true;

  public function PersistentUserData()
  {
    this._initializeCompletedEventObject = new EventObject(this, "INITIALIZE_COMPLETED");
    this._saveCompletedEventObject = new EventObject(this, "SAVE_COMPLETED");
    this._saveFailedEventObject = new EventObject(this, "SAVE_FAILED");
  }

  public function get initializeCompletedEventObject():EventObject
  {
    return this._initializeCompletedEventObject;
  }

  public function get saveCompletedEventObject():EventObject
  {
    return this._saveCompletedEventObject;
  }

  public function get saveFailedEventObject():EventObject
  {
    return this._saveFailedEventObject;
  }

  public function get sharedObjectFlushEnabled():Boolean
  {
    return this._sharedObjectFlushEnabled;
  }

  //Throws: Error if second call to initialize.
  public function initialize():void
  {
    if (this._sharedObjectPersist != null)
    {
      throw new Error("Cannot call initialize twice.");
    }

    this._sharedObjectPersist = new SharedObjectPersist("\codeHero");
    _sharedObjectPersist.openSucceededEventObject.addEventListener(persistOpenSucceededHandler);
    _sharedObjectPersist.openFailedEventObject.addEventListener(persistOpenFailedHandler);
    _sharedObjectPersist.flushSucceededEventObject.addEventListener(persistFlushSucceededHandler);
    _sharedObjectPersist.flushFailedEventObject.addEventListener(persistFlushFailedHandler);
    this._sharedObjectPersist.open();
  }

  private function persistOpenSucceededHandler(event:Event):void
  {
    var persist:IPersist = IPersist(event.target);
    persist.openSucceededEventObject.removeEventListener(persistOpenSucceededHandler);
    persist.openFailedEventObject.removeEventListener(persistOpenFailedHandler);

    load();

    switch (_userDataError)
    {
      case UserDataError.EMPTY:
        //Create a new id
        //Try to write it out.
        generateIdAndFlush();
        break;
      case UserDataError.CORRUPT:
        //If the id is still 000, create a new id
        //Try to write it out.
        generateIdAndFlush();
        break;
      case UserDataError.INCOMPATIBLE_VERSION:
        //If the id is still 000, create a new id
        //Try to write it out.
        generateIdAndFlush();
        break;
      case UserDataError.SUCCESS:
        this._initializeCompletedEventObject.dispatchEvent();
        break;
    }
  }

  private function load():UserDataError
  {
    return this.deserialize(this._sharedObjectPersist); //Deserialize defaults if this fails.
  }

  private function generateIdAndFlush():void
  {
    if (isUserIdGeneric())
    {
      useUniqueUserID();
    }

    this.serialize(this._sharedObjectPersist);
    this._sharedObjectPersist.flushSucceededEventObject.addEventListener(initializedFlushSucceededHandler);
    this._sharedObjectPersist.flushFailedEventObject.addEventListener(initializeFlushFailedHandler);
    this._sharedObjectPersist.flush();
  }

  private function persistOpenFailedHandler(event:Event):void
  {
    var persist:IPersist = IPersist(event.target);
    persist.openSucceededEventObject.removeEventListener(persistOpenSucceededHandler);
    persist.openFailedEventObject.removeEventListener(persistOpenFailedHandler);

    this._userDataError = UserDataError.OPEN_FAILED;
    this._initializeCompletedEventObject.dispatchEvent();
  }

  private function initializedFlushSucceededHandler(event:Event):void
  {
    this._sharedObjectPersist.flushSucceededEventObject.removeEventListener(initializedFlushSucceededHandler);
    this._sharedObjectPersist.flushFailedEventObject.removeEventListener(initializeFlushFailedHandler);

    this._userDataError = UserDataError.SUCCESS;
    this._initializeCompletedEventObject.dispatchEvent();
  }

  private function initializeFlushFailedHandler(event:Event):void
  {
    this._sharedObjectPersist.flushSucceededEventObject.removeEventListener(initializedFlushSucceededHandler);
    this._sharedObjectPersist.flushFailedEventObject.removeEventListener(initializeFlushFailedHandler);

    useGenericUserId();

    this._userDataError = UserDataError.FLUSH_FAILED;
    this._initializeCompletedEventObject.dispatchEvent();
  }

  public function save():void
  {
    if (this._sharedObjectFlushEnabled)
    {
      this.serialize(this._sharedObjectPersist);
      this._sharedObjectPersist.flush();
    }
    else //Pretend we succeeded
    {
      persistFlushSucceededHandler(null);
    }
  }

  public function persistFlushSucceededHandler(event:Event):void
  {
    this._userDataError = UserDataError.SUCCESS;
    this._saveCompletedEventObject.dispatchEvent();
  }

  private function persistFlushFailedHandler(event:Event):void
  {
    this._userDataError = UserDataError.FLUSH_FAILED;
    this._sharedObjectFlushEnabled = false;
    this._saveFailedEventObject.dispatchEvent();
  }
}
}